#ifndef __SOCK_HPP__
#define __SOCK_HPP__

#include "LogMessage.hpp"

#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cstring>
#include <memory>

class Socket {
private:
  static const int gBackLog = 20;    
public:
  static int SockInit() {
    int ret = socket(AF_INET, SOCK_STREAM, 0);
    if(ret < 0) {
      LogMessage(FATAL, _F, _L, "server create socket fail");
      exit(2);
    }

    LogMessage(DEBUG, _F, _L, "server create socket success,listenSock::%d", ret);

    return ret;  
  } 

  static void SockBind(int listenSock, uint16_t port, const std::string ip = "0.0.0.0") {
    sockaddr_in local;
    memset(&local, 0, sizeof(local));

    local.sin_addr.s_addr = inet_addr(ip.c_str());
    local.sin_family = AF_INET;
    local.sin_port = htons(port);

    if(bind(listenSock, reinterpret_cast<sockaddr*>(&local), sizeof(local)) < 0) {
      LogMessage(FATAL, _F, _L, "server bind IP+port fail:: %d:%s", errno, strerror(errno)); 
      exit(3);
    }
    LogMessage(DEBUG, _F, _L, "server bind IP+port success");
  }

  static void SockListen(int listenSock) {
    if(listen(listenSock, gBackLog) < 0) {
      LogMessage(FATAL, _F, _L, "server listen fail");
      exit(4);
    }
    LogMessage(NORMAL, _F, _L, "server init success");
  }

  static int SockAccept(int listenSock, std::string &clientIP, uint16_t &clientPort) {
    sockaddr_in clientMessage;
    socklen_t clientLen = sizeof(clientMessage);
    memset(&clientMessage, 0, clientLen);

    int serverSock = accept(listenSock, reinterpret_cast<sockaddr*>(&clientMessage), &clientLen);

    clientIP = inet_ntoa(clientMessage.sin_addr);
    clientPort = ntohs(clientMessage.sin_port);

    if(serverSock < 0) {
      LogMessage(ERROR, _F, _L, "server accept connection fail");
    } else {
      LogMessage(NORMAL, _F, _L, "server accept connection success::[%s:%d] serverSock::%d",\
          clientIP.c_str(), clientPort, serverSock);
    }

    return serverSock;
  }

};



#endif
